﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Net;

namespace QuanserClient
{
    /// <summary>
    /// Classe responsável pela conexão com o sistema de tanques da Quanser.
    /// Author: Amon Libanio da Silveira <amon.libanio@gmail.com>
    /// </summary>
    public class QuanserClient : IQuanserClient
    {
        private TcpClient socket;
        private QuanserServer server;
        private NetworkStream channel;

        public QuanserClient(QuanserServer _server)
        {
            this.server = _server;
        }

        public void Connect()
        {
            try
            {
                if (this.socket == null)
                {
                    this.socket = new TcpClient();
                    this.socket.Connect(server);
                    this.channel = new NetworkStream(this.socket.Client);
                }
            }
            catch (SocketException e)
            {
                // TODO Auto-generated catch block
                throw new QuanserClientException("Host nao encontrado!", e);
            }
            catch (IOException e)
            {
                throw new QuanserClientException("Erro de I/O!");
                // TODO Auto-generated catch block
            }
        }

        public void Disconnect()
        {
            try
            {
                if (this.socket != null)
                {
                    this.socket.Close();

                    this.socket = null;
                }
            }
            catch (SocketException e)
            {
                // TODO Auto-generated catch block
                throw new QuanserClientException("Erro na desconexão!", e);
            }
            catch (IOException e)
            {
                throw new QuanserClientException("Erro de I/O!");
                // TODO Auto-generated catch block
            }
        }


        /// <summary>
        /// Le o valor em volts que está no canal especificado.
        /// </summary>
        /// <param name="channel">channel Canal que deverá ter o valor lido</param>
        /// <returns> Retorna o valor no formato double do channel</returns>
        public double Read(int channel)
        {
            sendLine("READ " + channel + " ");

            String _toReturn = receiveLine();

            try
            {
                return Double.Parse(_toReturn.Replace(".", ","));
            }
            catch (FormatException ex)
            {
                throw new QuanserClientException("Erro ao receber dados. Erro de conversao de tipo (Not Float/Double)");
            }
        }

        /// <summary>
        /// Grava o valor especificado no canal. (Em volts)
        /// </summary>
        /// <param name="channel"> channel Canal que deverá ter o valor gravado.</param>
        /// <param name="value">value Valor a ser gravado no canal (double - em volts)</param>
        public void Write(int channel, double value)
        {
            sendLine("WRITE " + channel + " " + value.ToString().Replace(',', '.'));

            String _toReturn = receiveLine();

            if (!_toReturn.Contains("ACK"))
            {
                throw new QuanserClientException("Erro ao gravar na placa. Erro: [" + _toReturn + "]");
            }
        }


        private void sendLine(String _toSend)
        {
            try
            {
                if (!_toSend.Contains("\n"))
                {
                    _toSend += "\n";
                }
                if (channel.CanWrite)
                {
                    StreamWriter _streamWriter = new StreamWriter(this.channel);
                    _streamWriter.Write(_toSend);
                    _streamWriter.Flush();
                }                
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                throw new QuanserClientException("Erro de I/O ao enviar dados.");
            }
        }

        private String receiveLine()
        {
            StreamReader _streamReader = new StreamReader(this.channel);

            try
            {
                return _streamReader.ReadLine();
            }
            catch (IOException e)
            {
                throw new QuanserClientException("Erro de I/O ao receber dados");
            }
        }
    }
}
